package br.com.officium.util;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import org.joda.time.*;

/**
 * Utility class for Dates. Everything related to dates must be here.
 * 
 * @author Ivo
 */
public final class DateUtil {

    public static final String FORMAT_DATE_TIME = "dd/MM/yyyy - HH:mm";
    public static final String FORMAT_DATE_SQL = "yyyy-MM-dd";
    public static final String FORMAT_TIME = "HH:mm";

    private DateUtil() {
        // Private constructor so others can't instatiate it.
    }
    
    public static int getAge(Date dateBirth) {
        
        // Create a calendar object with the date of birth
        Calendar dateOfBirth = new GregorianCalendar();
        dateOfBirth.setTime(dateBirth);

        // Create a calendar object with today's date
        Calendar today = Calendar.getInstance();

        // Get age based on year
        int age = today.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR);

        // Add the tentative age to the date of birth to get this year's birthday
        dateOfBirth.add(Calendar.YEAR, age);

        // If this year's birthday has not happened yet, subtract one from age
        if (today.before(dateOfBirth)) {
            age--;
        }
        
        return age;
    }

    public static boolean isTodayBetween(Date begin, Date end) {

        Calendar today = Calendar.getInstance();
        return isDateBetween(today.getTime(), begin, end);

    }

    public static boolean isDateBetween(Date date, Date begin, Date end) {

        boolean isBetween = false;

        if (begin != null && end != null) {

            if (date.after(begin) && date.before(end)) {
                isBetween = true;
            }

        }

        return isBetween;
    }

    /**
     * Retorna o número de dias COMPLETOS de diferença entre as datas.
     * 
     * @param begin
     * @param end
     */
    public static int getDaysBetween(Date begin, Date end) {
        DateTime date1 = new DateTime(begin);
        DateTime date2 = new DateTime(end);

        return Days.daysBetween(date1, date2).getDays();
    }

    /**
     * Retorna o número de horas COMPLETAS de diferença entre as datas.
     * 
     * @param begin
     * @param end
     */
    public static int getHoursBetween(Date begin, Date end) {
        DateTime date1 = new DateTime(begin);
        DateTime date2 = new DateTime(end);

        return Hours.hoursBetween(date1, date2).getHours();
    }

    /**
     * Retorna o número de minutos COMPLETOS de diferença entre as datas.
     * 
     * @param begin
     * @param end
     */
    public static int getMinutesBetween(Date begin, Date end) {
        DateTime date1 = new DateTime(begin);
        DateTime date2 = new DateTime(end);

        return Minutes.minutesBetween(date1, date2).getMinutes();
    }

    /**
     * Retorna o número de segundos COMPLETOS de diferença entre as datas.
     * 
     * @param begin
     * @param end
     */
    public static int getSecondsBetween(Date begin, Date end) {
        DateTime date1 = new DateTime(begin);
        DateTime date2 = new DateTime(end);

        return Seconds.secondsBetween(date1, date2).getSeconds();
    }

    /**
     * Gets the date formatter with the default formatting style for the default
     * locale.
     * 
     * @param date
     */
    public static Date convertDate(String date) {
        DateFormat format = DateFormat.getDateInstance();
        format.setLenient(false);

        try {
            return new Date(format.parse(date).getTime());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param dtConsulta
     * @return String no formato "yyyy-MM-dd"
     */
    public static String convertDate(Date dtConsulta) {

        return convertDateTime(dtConsulta, FORMAT_DATE_SQL);

    }

    /**
     * @param dtConsulta
     * @return String no formato "HH:mm:ss"
     */
    public static String convertTime(Date dtConsulta) {

        return convertDateTime(dtConsulta, FORMAT_TIME);

    }

    /**
     * @param dtConsulta
     * @return String no formato "dd/MM/yyyy - HH:mm:ss"
     */
    public static String outputDate(Date dtConsulta) {

        return convertDateTime(dtConsulta, FORMAT_DATE_TIME);

    }

    private static String convertDateTime(Date dt, String format) {
        try {
            SimpleDateFormat formatter = new SimpleDateFormat(format,
                    new Locale("pt", "BR"));
            return formatter.format(dt);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Retorna a data passada por parametro somada do número de horas também
     * passado por parametro.
     * 
     * @param date
     * @param seconds
     * @return
     */
    public static Date addSeconds(Date date, int seconds) {

        DateTime d = new DateTime(date);
        d = d.plusSeconds(seconds);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro somada do número de minutos também
     * passado por parametro.
     * 
     * @param date
     * @param minutes
     * @return
     */
    public static Date addMinutes(Date date, int minutes) {

        DateTime d = new DateTime(date);
        d = d.plusMinutes(minutes);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro somada do número de horas também
     * passado por parametro.
     * 
     * @param date
     * @param hours
     * @return
     */
    public static Date addHours(Date date, int hours) {

        DateTime d = new DateTime(date);
        d = d.plusHours(hours);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro somada do número de dias também
     * passado por parametro.
     * 
     * @param date
     * @param days
     * @return
     */
    public static Date addDays(Date date, int days) {

        DateTime d = new DateTime(date);
        d = d.plusDays(days);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro somada do número de meses também
     * passado por parametro.
     * 
     * @param date
     * @param months
     * @return
     */
    public static Date addMonths(Date date, int months) {

        DateTime d = new DateTime(date);
        d = d.plusMonths(months);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro somada do número de meses também
     * passado por parametro.
     * 
     * @param date
     * @param months
     * @return
     */
    public static Date minusMonths(Date date, int months) {

        DateTime d = new DateTime(date);
        d = d.minusMonths(months);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro subtraída do número de dias também
     * passado por parametro.
     * 
     * @param date
     * @param days
     * @return
     */
    public static Date minusDays(Date date, int days) {

        DateTime d = new DateTime(date);
        d = d.minusDays(days);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro subtraída do número de horas também
     * passado por parametro.
     * 
     * @param date
     * @param hours
     * @return
     */
    public static Date minusHours(Date date, int hours) {

        DateTime d = new DateTime(date);
        d = d.minusHours(hours);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro subtraída do número de minutos
     * também passado por parametro.
     * 
     * @param date
     * @param minutes
     * @return
     */
    public static Date minusMinutes(Date date, int minutes) {

        DateTime d = new DateTime(date);
        d = d.minusMinutes(minutes);

        return d.toDate();
    }

    /**
     * Retorna a data passada por parametro subtraída do número de segundos
     * também passado por parametro.
     * 
     * @param date
     * @param seconds
     * @return
     */
    public static Date minusSeconds(Date date, int seconds) {

        DateTime d = new DateTime(date);
        d = d.minusSeconds(seconds);

        return d.toDate();
    }

    /**
     * Método para checar se date2 é anterior a date1.
     * 
     * @param date1
     * @param date2
     * @return true if the second date2 is before than date1. False otherwise.
     */
    public static boolean isBefore(Date date1, Date date2) {

        boolean isBefore = false;

        if (date2.before(date1)) {
            isBefore = true;
        }

        return isBefore;
    }

    /**
     * Metodo para informar se a data passada por parametro é anterior a data
     * atual.
     * 
     * @param date
     * @return TRUE if the date is before the actual date (now). FALSE
     *         otherwise.
     */
    public static boolean isBeforeNow(Date date) {

        Calendar today = Calendar.getInstance();
        return isBefore(today.getTime(), date);

    }

    /**
     * Classe interna para ordenar uma lista de datas.
     */
    static class DateCompare implements Comparator<Date> {

        @Override
        public int compare(Date one, Date two) {
            return one.compareTo(two);
        }
    }

    /**
     * Método para ordenar uma lista de datas da menor para a maior.
     * 
     * @param unsortedDates
     * @return lista de datas ordenada
     */
    public static List<Date> dateSort(List<Date> unsortedDates) {
        Collections.sort(unsortedDates, new DateCompare());
        return unsortedDates;
    }
}
